#ifndef BlackScholesPricer_hpp
#define BlackScholesPricer_hpp

#include "timeSequence.hpp"
#include "timeSequenceHolder.hpp"
#include "ForwardRateSequence.hpp"
#include "standardFunctions.hpp"
#include "cmath"

namespace TermStructure {
    template<typename TVarianceStructure, typename T, typename TSize = long>
    class BlackScholesPricer:public TimeSequenceHolder<T,TSize>
    {
        ErrorFunction<T> _erf;
        T _ncdf(T x)
        {
            return 0.5*(1+this->_erf(x/M_SQRT2));
        }
    public:
        T PriceCaplet(const ForwardRateSequence<T,TSize> &f, const TVarianceStructure &varianceStructure, T Strike, TSize ChooserIndex, TSize CurrentTimeIndex = 0)
        {
			if(f.ForwardRateAt(ChooserIndex +1) <=0) return 0;
            if(! f.IsDiscountFactorEstablished()) 
            {
             f.EstablishDiscountFactors();   
            }
            T currentT = this->_timeSequence->GetTime(CurrentTimeIndex);
            T chooserT = this->_timeSequence->GetTime(ChooserIndex);
            T varT = varianceStructure.VolatilityIntegrator(currentT, chooserT, ChooserIndex + 1, ChooserIndex + 1);
            return f.DiscountFactorAt(ChooserIndex+1,CurrentTimeIndex)*
            (f[ChooserIndex+1]*_ncdf((log(f[ChooserIndex+1]/Strike) + 0.5 * varT)/sqrt(varT)) - Strike*_ncdf((log(f[ChooserIndex+1]/Strike)-0.5 * varT)/sqrt(varT)))* this->_timeSequence->TimeDifference(ChooserIndex+1);
        }
        T PriceCap(const ForwardRateSequence<T,TSize> &f, const TVarianceStructure &varianceStructure, T Strike, TSize EndIndex, TSize EnterIndex = 0, TSize CurrentTimeIndex = 0)
        {
            T result = 0;
            for(TSize i = EnterIndex + 1; i < EndIndex - 1; i++)
            {
                result += PriceCaplet(f, varianceStructure, i, CurrentTimeIndex);
            }
            return result;
        }
    };
}

#endif
